import time

from ..exception.TestException import TestException
from ..common.ui.PageElement import PageElement
import traceback
from robot.api import logger

from ..exception.errorcode import ErrorCode


class Grid(PageElement):
    _fish_data_ui_role = 'grid'

    def setValue(self, *params):
        self.select(*params)

    def select(self, *params):
        self.wait_element_presence()
        self.check_fish_data_role_id()
        for i in range(5):
            try:
                is_tree_grid = self.__is_treegrid()
                if is_tree_grid:
                    # 每次只能设置一个值，防止名称冲突
                    self._tree_grid_select(*params)
                else:
                    self._grid_select(*params)
                break
            except Exception as e:
                logger.error(traceback.format_exc())
                if i >= 4:
                    raise TestException.by_exception(e)

    def _tree_grid_select(self, *params):
        check_col = self._match_check_col(*params)
        if check_col is None:
            # 如果第一个参数不是colLabel，则则设置explan_column作为检查
            check_col = self.__get_expland_column()
        else:
            params = params[1:]
        check_nodes = self.__get_root_nodes()
        keyname = self.__get_keyname()
        check_rowid = None
        for param in params:
            exist = False
            for data in check_nodes:
                if (data[check_col] == param):
                    exist = True
                    check_rowid = data[keyname]
                    self.__click_tree_expand(check_rowid)
                    check_nodes = self.__get_child_node(check_rowid)
                    break
            if not exist:
                raise TestException.by_error_code(ErrorCode.GRID_VALUE_NOT_EXIST, value=param)
        self.__set_checkrow(check_rowid)

    def _grid_select(self, *params):
        if not len(params) == 2:
            raise TestException.by_error_code(ErrorCode.GRID_PARAMS_ERROR)
        check_col_label = params[0]
        check_col_value = params[1]
        key_name = self.__get_keyname()
        col_name = self._get_match_col_name(check_col_label)
        rowid = None
        page_count = self.__page_count()
        backend_pager = self.__backend_pager()
        if backend_pager:
            for page_index in range(1, int(page_count) + 1): #将page_count转化为int, 否则走到该分支会报TypeError
                logger.debug("choose page {0}".format(page_index))
                self.__select_page(page_index)
                rowid = self._get_match_row_id(backend_pager, col_name, check_col_value, key_name)
                if rowid and self.__select_rowid(rowid):
                    self.__set_checkrow(rowid)
                    break
        else:
            logger.debug("not backend")
            rowid = self._get_match_row_id(backend_pager, col_name, check_col_value, key_name)
            if rowid:
                script = "$(arguments[0]).grid('setSelection','{0}')".format(str(rowid))
                self._execute_script(script, self._get_web_element())
                for page_index in range(1, int(page_count) + 1):
                    self.__select_page(page_index)
                    if self.__select_rowid(rowid):
                        self.__set_checkrow(rowid)
                        break
        if not rowid:
            raise TestException.by_error_code(ErrorCode.GRID_VALUE_NOT_FIND, value=check_col_value,
                                              label=check_col_label)

    def _get_match_col_name(self, check_col_label: str) -> str:
        col_name = None
        col_model = self.__get_colmodel()
        for col in col_model:
            if col['label'] == check_col_label:
                col_name = col['name']
                break
        if col_name is None:
            # 直接通过界面元素查找
            script = "return $(arguments[0]).find('.ui-jqgrid-hdiv').find('table').find('thead')" \
                     ".find('th[title*=\"{title}\"]').attr('id');".format(title=check_col_label)
            col_id = self._execute_script(script, self._get_web_element())
            if col_id is not None:
                col_name = col_id[col_id.rindex('_') + 1:]
        if col_name is None:
            raise TestException.by_error_code(ErrorCode.GRID_COLUMN_LABEL_NOT_FIND, value=check_col_label)
        return col_name

    def _get_match_row_id(self, backend_loading, col_name: str, check_col_value: str, key_name: str) -> str:
        """
        通过check_col_value匹配rowid
        :param backend_loading: 是否后台加载，需要等待datasource加载
        :param col_name:
        :param check_col_value:
        :param key_name:
        :return:
        """
        rowid = None
        data_source = self.__get_datasource(50) if backend_loading else self.__get_datasource()
        logger.info("page datasource value {0}".format(data_source))
        for data in data_source:
            logger.debug("compare value {0}".format(data[col_name]))
            if data[col_name] == check_col_value:
                logger.debug("find match {0}".format(check_col_value))
                rowid = data[key_name]
                break
        if rowid is None:
            # 如果datasource找不到，则value值很可能是修饰过的，则直接从tbody>td[title="col_value"].parent(tr).attr(id)获取rowid
            script = "return $(arguments[0]).find('tbody').find('td[title=\"{title}\"]').parent('tr').attr('id')".format(
                title=check_col_value)
            rowid = self._execute_script(script, self._get_web_element())
        return rowid

    def __set_checkrow(self, rowid):
        is_multiselect = self.__is_multiselect()
        if is_multiselect:
            # 开发不规范自定义事件响应处理，只能通过click()去触发，不能通过setCheckRows
            script = self.__get_tr_element_script(rowid=rowid, append=".find('input').click()")
            self._execute_script(script, self._get_web_element())
        else:
            script = self.__get_tr_element_script(rowid=rowid, append=".find('.jqgrid-cbox').find('input').size()")
            size = self._execute_script(script, self._get_web_element())
            if size is not None and size == 1:
                script = self.__get_tr_element_script(rowid=rowid, append=".find('.jqgrid-cbox').find('input').click()")
                self._execute_script(script, self._get_web_element())
            else:
                script = self.__get_tr_element_script(rowid=rowid, append=".click()")
                self._execute_script(script, self._get_web_element())

    def __get_datasource(self, loop: int = 1, sleep: int = 0.1):
        datasource = None
        for index in range(1, loop + 1):
            time.sleep(sleep)
            datasource = self.__get_option('data')
            if datasource:
                break
        return datasource

    def __get_keyname(self):
        return self.__get_option('keyName')

    def __is_treegrid(self):
        return self.__get_option('treeGrid')

    def __is_multiselect(self):
        return self.__get_option('multiselect')

    def __get_expland_column(self):
        return self.__get_option('expandColumn')

    def __get_option(self, option):
        script = "return $(arguments[0]).grid('option','{0}')".format(option)
        return self._execute_script(script, self._get_web_element())

    def __get_child_node(self, rowid: str, loop: int = 5, sleep: int = 0.1):
        """
        获取子节点的时候要注意后端异步加载，需要等待查询
        :param rowid:
        :param loop:
        :param sleep:
        :return:
        """
        child_node = None
        for index in range(1, loop + 1):
            time.sleep(sleep)
            script = "node = $(arguments[0]).grid('getRowData', '{rowid}'); " \
                     "return $(arguments[0]).grid('getNodeChildren', node)".format(rowid=rowid)
            child_node = self._execute_script(script, self._get_web_element())
            if child_node:
                break
        return child_node

    def __click_tree_expand(self, rowid: str):
        """
        处理懒加载时候需要点击folder
        :param rowid:
        :return:
        """
        script = self.__get_tr_element_script(prefix='return ', rowid=rowid, append='.size()')
        size = self._execute_script(script, self._get_web_element())
        if size != 0:
            script = self.__get_tr_element_script(rowid=rowid, append=".find('.treeclick').click()")
            self._execute_script(script, self._get_web_element())
            return True
        else:
            return False

    def __get_root_nodes(self):
        script = "return $(arguments[0]).grid('getRootNodes')"
        return self._execute_script(script, self._get_web_element())

    def expand_all(self):
        script = "$(arguments[0]).grid('expandAll')"
        self._execute_script(script, self._get_web_element())

    def __get_colmodel(self) -> str:
        return self.__get_option('colModel')

    def __page_count(self, loop: int = 5, sleep: float = 0.5) -> int:
        page_count = None
        for index in range(1, loop + 1):
            time.sleep(sleep)
            page_count = self.__get_option('lastpage')
            if page_count:
                break
        return page_count

    def __select_page(self, page: int):
        script = "$(arguments[0]).find('div[data-ui-role=\"pagination\"]')" \
                 ".children('.pagination')" \
                 ".children('li[data-page=\"{0}\"]')" \
                 ".click()".format(page)
        return self._execute_script(script, self._get_web_element())

    def __select_rowid(self, rowid) -> bool:
        script = self.__get_tr_element_script(prefix='return ', rowid=rowid, append='.size()')
        size = self._execute_script(script, self._get_web_element())
        if size != 0:
            # script = self.__get_tr_element_script(rowid=rowid, append='.find(\'.jqgrid-cbox\').find(\'input\').click()')
            # self._execute_script(script, self._get_web_element())
            return True
        else:
            return False

    def __get_tr_element_script(self, rowid: str, append: str = '', prefix='') -> str:
        return "{prefix} $(arguments[0]).find('tr[id=\"{rowid}\"]'){append}".format(rowid=str(rowid), append=append,
                                                                                    prefix=prefix)

    def __backend_pager(self) -> bool:
        """
        判断是否为后端分页
        :return:
        """
        script = "return typeof $(arguments[0]).grid('option','pageData')"
        return self._execute_script(script, self._get_web_element()) == 'function'

    def __edit_row(self, rowid):
        script = "return $(arguments[0]).grid('editRow','{0}')".format(rowid)
        self._execute_script(script, self._get_web_element())

    def _match_check_col(self, *params):
        """
        检查第一个参数是否为colLabel，如果是，则返回colName
        :param params:
        :return:
        """
        colName = None
        if len(params) > 1:
            check_param = params[0]
            col_model = self.__get_colmodel()
            for col in col_model:
                if col['label'] == check_param:
                    colName = col['name']
                    break
        return colName

    def get_identification(self):
        identification = {'data-ui-role': ['grid']}
        return identification
